/**
实现地图上一视图下一视图的切换及其持久化存储
*/
<template>
    <div class="wrap">
        <div ref="map" id="map"></div>
        <el-button-group>
            <el-button type="primary" @click="switchPrev">上一视图</el-button>
            <el-button type="primary" @click="switchNext">下一视图</el-button>
            <el-button type="primary" @click="pointNorth">指北</el-button>
        </el-button-group>
    </div>

</template>

<script>
    import "ol/ol.css";
    import {Map, View} from "ol";
    import TileLayer from "ol/layer/Tile";
    import XYZ from "ol/source/XYZ";
    import Collection from 'ol/Collection.js';
    import {unlistenByKey} from 'ol/events';

    const MAX_LENGTH = 5;
    export default {
        name: "ViewSwitch",
        data() {
            this.viewStates = new Collection();
            this.currentStateIndex = -1;
            this.moveEndEvtKey = null;
            this.pointerDragOrWheelEvtKey = null;
            return {
                map: null,
            };
        },

        created() {
            const viewStatesStorage = JSON.parse(localStorage.getItem('viewStates')) || [];
            this.viewStates.extend(viewStatesStorage);
        },

        mounted() {
            // 创建地图
            this.initMap();

            const length = this.viewStates.getLength();
            if (length > 0) {
                const currentIdx = Number(localStorage.getItem('activeIndex'));
                this.restoreViewState(currentIdx);
                this.currentStateIndex = currentIdx;
                this.map.once('rendercomplete', this.bindMapMoveEndEvt);
            } else {
                this.bindMapMoveEndEvt();
            }
        },

        methods: {
            /**
             * 初始化一个 openlayers 地图
             */
            initMap() {
                this.map = new Map({
                    target: "map",
                    view: new View({
                        center: [113.5, 34.7],
                        zoom: 10,
                        projection: "EPSG:4326",
                    }),
                });

                var gaodeLayer = new TileLayer({
                    source: new XYZ({
                        url: "http://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
                    })
                });
                this.map.addLayer(gaodeLayer);
            },

            //给地图绑定移动结束事件
            bindMapMoveEndEvt() {
                this.moveEndEvtKey = this.map.on('moveend', this.saveViewState);
            },
            //保存视图状态
            // saveViewState() {
            //     if ((this.viewStates.getLength() - 1) === MAX_LENGTH) {//若超限，则删除第一个视图状态
            //         this.viewStates.removeAt(0);
            //         this.currentStateIndex--;
            //     }
            //     const viewState = this.getMapViewState();
            //     this.viewStates.insertAt(this.currentStateIndex + 1, viewState);
            //     localStorage.setItem('viewStates', JSON.stringify(this.viewStates.getArray()));
            //     this.currentStateIndex++;
            //     localStorage.setItem('activeIndex', this.currentStateIndex);
            // },
            saveViewState() {
                if ((this.viewStates.getLength() - 1) === MAX_LENGTH) {//若超限，则删除第一个视图状态
                    this.viewStates.removeAt(0);
                    this.currentStateIndex--;
                }
                const viewState = this.getMapViewState();
                const currViewState = this.viewStates.getArray()[this.currentStateIndex];
                //若不相同再存储 <==========解决办法
                if (!this.objectsAreEqual(viewState, currViewState)) {
                    this.viewStates.insertAt(this.currentStateIndex + 1, viewState);
                    localStorage.setItem('viewStates', JSON.stringify(this.viewStates.getArray()));
                    this.currentStateIndex++;
                    localStorage.setItem('activeIndex', this.currentStateIndex);
                }
            },
            //检查两个对象键值和属性是否完全相同
            objectsAreEqual(oneObj, anotherObj) {
                // 检查两个输入是否都是对象
                if (typeof oneObj !== 'object' || oneObj === null || typeof anotherObj !== 'object' || anotherObj === null) {
                    return false;
                }

                // 获取对象的键
                const oneKeys = Object.keys(oneObj);
                const anotherKeys = Object.keys(anotherObj);

                // 检查键的数量是否相同
                if (oneKeys.length !== anotherKeys.length) {
                    return false;
                }

                // 遍历键并比较值
                for (const key of oneKeys) {
                    // 检查键是否存在于两个对象中，并且它们的值是否相等
                    if (!anotherKeys.includes(key) || oneObj[key] !== anotherObj[key]) {
                        return false;
                    }
                }
                return true;
            },

            //获取视图的center, zoom, rotation
            getMapViewState() {
                const mapView = this.map.getView();
                const center = mapView.getCenter();
                const zoom = mapView.getZoom();
                const rotation = mapView.getRotation();
                return {center, zoom, rotation};
            },
            //切换为上一视图
            switchPrev() {
                if (this.currentStateIndex === 0) {
                    this.$message.error('已到第一个视图');
                }
                if (this.currentStateIndex > 0) {
                    this.restoreViewState(this.currentStateIndex - 1);
                    this.currentStateIndex--;
                }
            },
            //切换为下一视图
            switchNext() {
                if (this.currentStateIndex === (this.viewStates.getLength() - 1)) {
                    this.$message.error('已到最后一个视图');
                }
                if (this.currentStateIndex < this.viewStates.getLength() - 1) {
                    this.restoreViewState(this.currentStateIndex + 1);
                    this.currentStateIndex++;
                }
            },
            //恢复为某一视图状态
            restoreViewState(index) {
                unlistenByKey(this.moveEndEvtKey);
                const viewState = this.viewStates.getArray()[index];
                const {center, zoom, rotation} = viewState;
                this.map.getView().animate({center, zoom, rotation, duration: 500});
                localStorage.setItem('activeIndex', index);
                //在点击视图切换按钮之后记得绑定鼠标拖拽或滚动滑动时打开地图移动事件
                unlistenByKey(this.pointerDragOrWheelEvtKey);
                this.pointerDragOrWheelEvtKey = this.map.once(['pointerdrag', 'wheel'], () => {
                    this.bindMapMoveEndEvt();
                });
            },
            //指北
            pointNorth() {
                unlistenByKey(this.moveEndEvtKey);
                this.bindMapMoveEndEvt();
                const view = this.map?.getView();
                if (view && view.getRotation()) {
                    view.setRotation(0);
                }
            },
        },

        beforeDestroy() {
            unlistenByKey(this.moveEndEvtKey);
            unlistenByKey(this.pointerDragOrWheelEvtKey);
        },
    };

</script>

<style scoped>
    #map {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
    }

    /*移除OSM的链接*/
    :deep(.ol-attribution) {
        display: none;
    }
</style>